package com.wzdigit.wms.raw.service.inv;

import com.alibaba.fastjson.JSON;
import com.wzdigit.framework.Shift;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.wms.basic.client.request.inv.SearchGoodsConverInfoRequest;
import com.wzdigit.wms.basic.client.request.inv.SubmitGoodsConverRequest;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.inv.GoodsConverInfoResponse;
import com.wzdigit.wms.basic.domain.basic.Sku;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inventory.GoodsLog;
import com.wzdigit.wms.basic.domain.inventory.GoodsVersion;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.domain.order.TrsnDtl;
import com.wzdigit.wms.basic.domain.order.TrsnDtlGoods;
import com.wzdigit.wms.basic.domain.order.TrsnHeader;
import com.wzdigit.wms.basic.domain.transfer.TransferDtl;
import com.wzdigit.wms.basic.domain.transfer.TransferDtlGoods;
import com.wzdigit.wms.basic.domain.transfer.TransferHeader;
import com.wzdigit.wms.basic.enums.GoodsStatusEnum;
import com.wzdigit.wms.basic.enums.IsHoldEnum;
import com.wzdigit.wms.basic.enums.OpCodeEnum;
import com.wzdigit.wms.basic.enums.QaStatusEnum;
import com.wzdigit.wms.basic.enums.TransferDtlGoodStatusEnum;
import com.wzdigit.wms.basic.enums.TransferDtlStatusEnum;
import com.wzdigit.wms.basic.enums.TransferHeaderStatusEnum;
import com.wzdigit.wms.basic.enums.TransferNoCodeEnum;
import com.wzdigit.wms.basic.enums.TransferTypeEnum;
import com.wzdigit.wms.basic.enums.TrsnDtlInvUpdateFlagEnum;
import com.wzdigit.wms.basic.enums.TrsnDtlStatusEnum;
import com.wzdigit.wms.basic.enums.TrsnHeaderStatusEnum;
import com.wzdigit.wms.basic.enums.TrsnNoteTypeEnum;
import com.wzdigit.wms.basic.mapper.core.basic.SkuMapper;
import com.wzdigit.wms.basic.mapper.core.basic.WarehouseMapper;
import com.wzdigit.wms.basic.mapper.core.inventory.manager.GoodsConverMapper;
import com.wzdigit.wms.basic.mapper.core.order.TrsnDtlGoodsMapper;
import com.wzdigit.wms.basic.mapper.core.order.TrsnDtlMapper;
import com.wzdigit.wms.basic.mapper.core.order.TrsnHeaderMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.TransferDtlGoodsMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.TransferDtlMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.TransferHeaderMapper;
import com.wzdigit.wms.basic.service.code.GoodsVersionService;
import com.wzdigit.wms.basic.service.code.InventoryService;
import com.wzdigit.wms.basic.service.code.LotnoService;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.raw.exception.SystemException;
import com.wzdigit.wms.raw.service.backtosap.MaterialReplaceWriteOffService;
import com.wzdigit.wms.raw.service.mid.MappingHouseService;
import com.wzdigit.wms.raw.service.wmscommon.core.GoodsService;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import com.wzdigit.wms.web.service.wms2sap.materialreplace.ZDT_085_ReqRECORDHEAD;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 料号转换-服务类
 * 
 * @author yangdongjie
 * @GdnService.java
 * @2021年2月24日下午3:25:03
 */
@Service
public class GoodsConverService {

	@Autowired
	private GoodsConverMapper goodsConverMapper;
	
	@Autowired
	private SkuMapper skuMapper;
	
	@Autowired
	private WarehouseMapper warehouseMapper;
	
	@Autowired
	private GoodsService goodsService;
	
	@Autowired
	private GoodsVersionService goodsVersionService;
	
	@Autowired
	private TransferHeaderMapper transferHeaderMapper;
	
	@Autowired
	private TransferDtlMapper transferDtlMapper;
	
	@Autowired
	private TransferDtlGoodsMapper transferDtlGoodsMapper;
	
	@Autowired
    private TrsnHeaderMapper trsnHeaderMapper;
	
	@Autowired
    private TrsnDtlMapper trsnDtlMapper;
	
	@Autowired
	private TrsnDtlGoodsMapper trsnDtlGoodsMapper;
	
	@Autowired
	private LotnoService lotnoService;
	
	@Autowired
	private InventoryService inventoryService;

	@Autowired
	private MappingHouseService mappingHouseService;

	@Autowired
	private MaterialReplaceWriteOffService materialReplaceWriteOffService;
	
	@Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
    private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;
	
	private final static String TRSN_ORDER = "TRSN_ORDER";

	/**
	 * 扫描SN
	 * 
	 * @param dto
	 * @return
	 */
	public GoodsConverInfoResponse scanInfo(SearchGoodsConverInfoRequest dto) {
		GoodsConverInfoResponse goods = goodsConverMapper.selectInfoBySn(dto.getGoodsSn());
		// 【检验1】条码不存在
		if(goods == null) {
			Shift.fatal(String.format("SN[%s]条码不存在", dto.getGoodsSn()));
		}
		// 【检验2】待转换物料编码必须一致
		if(dto.getSkuId() != null) {
			if(!Objects.equals(goods.getSkuId(), dto.getSkuId())) {
				Shift.fatal(String.format("SN[%s]物料[%s]与待转换物料列表中的物料不一致，不能一起转换", goods.getGoodsSn(), goods.getSkuCode()));
			}
		}
		// 【检验3】待转换物料所属仓库必须一致
		if(dto.getWhsId() != null) {
			if(!Objects.equals(goods.getWhsId(), dto.getWhsId())) {
				Shift.fatal(String.format("SN[%s]所属仓库[%s]与待转换物料列表中的SN所属仓库不一致，不能一起转换", goods.getGoodsSn(), goods.getWhsName()));
			}
		}
		// 【检验4】待转换物料的组织必须一致
		if (dto.getFactory() != null) {
			if (!Objects.equals(goods.getFactory(), dto.getFactory())) {
				Shift.fatal(String.format("SN[%s]工厂组织[%s]与待转换物料列表中的SN工厂组织不一致，不能一起转换", goods.getGoodsSn(), goods.getFactory()));
			}
		}
		// 【检验6】待入库/已拣选/已出库/在途/已报废    状态不可进行料号转换
		if(Objects.equals(goods.getStatus(), GoodsStatusEnum.WAIT_IN.code) || 
				Objects.equals(goods.getStatus(), GoodsStatusEnum.HAS_DOWN.code) || 
				Objects.equals(goods.getStatus(), GoodsStatusEnum.HAS_CHUKU.code) || 
				Objects.equals(goods.getStatus(), GoodsStatusEnum.OUT_ONLOAD.code) ||
				Objects.equals(goods.getStatus(), GoodsStatusEnum.SCRAP.code)) {
			Shift.fatal(String.format("SN[%s]状态为[%s]不可进行料号转换", goods.getGoodsSn(), GoodsStatusEnum.getEnumByCode(goods.getStatus()).enumName));
		}
		// 【检验7】冻结状态下的SN不能进行料号转换
		if (Objects.equals(goods.getIsHold(), IsHoldEnum.Yes.code)) {
			Shift.fatal(String.format("SN[%s]被冻结不可进行料号转换", goods.getGoodsSn()));
		}
		// 【检验8】物料品质状态必须为“合格”
		if (!Objects.equals(goods.getQaStatus(), QaStatusEnum.OK.code)) {
			Shift.fatal(String.format("SN[%s]品质状态为[%s]，不能进行料号转换", goods.getGoodsSn(), QaStatusEnum.getEnumByCode(goods.getQaStatus()).enumName));
		}
		return goods;
	}
	
	/**
	 * 确认提交
	 * 
	 * @param dto
	 * @param servletRequest
	 * @return
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result<?> submit(SubmitGoodsConverRequest dto, HttpServletRequest servletRequest) throws Exception {
		List<GoodsVersion> goodsList = goodsVersionService.selectBySnList(dto.getSnList());
				
		// 【检验1】待转换物料编码必须一致
		List<GoodsVersion> errorList = goodsList.stream().filter(t -> !Objects.equals(t.getSkuId(), dto.getOriginalSkuId())).collect(Collectors.toList());
		if(errorList.size() > 0) {
			List<String> errorSnList = errorList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
			List<Integer> skuIdList = errorList.stream().map(t -> t.getSkuId()).collect(Collectors.toList());
			List<String> skuCodeList = skuMapper.getSkuCodeBySkuIdList(skuIdList);
			String message = String.format("SN属性发生变更，SN%s物料%s与待转换物料列表中的物料不一致，不能一起转换！", errorSnList.toString(), skuCodeList.toString());
			return new Result<>(false, message);
		}
		
		// 【检验2】待转换物料所属仓库必须一致
		errorList = goodsList.stream().filter(t -> !Objects.equals(t.getWhsId(), dto.getOriginalWhsId())).collect(Collectors.toList());
		if(errorList.size() > 0) {
			List<String> errorSnList = errorList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
			List<Integer> whsIdList = errorList.stream().map(t -> t.getWhsId()).collect(Collectors.toList());
			List<String> whsNameList = warehouseMapper.getWhsNameByWhsIdList(whsIdList);
			String message = String.format("SN属性发生变更，SN%s所属仓库%s与待转换物料列表中的SN所属仓库不一致，不能一起转换！", errorSnList.toString(), whsNameList.toString());
			return new Result<>(false, message);
		}
		
		// 【检验3】待转换物料工厂组织必须一致
		errorList = goodsList.stream().filter(t -> !Objects.equals(t.getFactory(), dto.getOriginalFactory())).collect(Collectors.toList());
		if(errorList.size() > 0) {
			List<String> errorSnList = errorList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
			List<String> factoryList = errorList.stream().map(t -> t.getFactory()).collect(Collectors.toList());
			String message = String.format("SN属性发生变更，SN%s工厂组织%s与待转换物料列表中的SN工厂组织不一致，不能一起转换！", errorSnList.toString(), factoryList.toString());
			return new Result<>(false, message);
		}
		
		// 【检验4】待入库/已拣选/已出库/在途/已报废    状态不可进行料号转换
		errorList = goodsList.stream().filter(t -> Objects.equals(t.getStatus(), GoodsStatusEnum.WAIT_IN.code) || 
				Objects.equals(t.getStatus(), GoodsStatusEnum.HAS_DOWN.code) || 
				Objects.equals(t.getStatus(), GoodsStatusEnum.HAS_CHUKU.code) || 
				Objects.equals(t.getStatus(), GoodsStatusEnum.OUT_ONLOAD.code) ||
				Objects.equals(t.getStatus(), GoodsStatusEnum.SCRAP.code)).collect(Collectors.toList());
		if (errorList.size() > 0) {
			List<String> errorSnList = errorList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
			List<Integer> statusList = errorList.stream().map(t -> t.getStatus()).collect(Collectors.toList());
			List<String> statusNameList = GoodsStatusEnum.getEnumNameByCodeList(statusList);
			String message = String.format("SN属性发生变更，SN%s状态为%s不可进行料号转换！", errorSnList.toString(), statusNameList.toString());
			return new Result<>(false, message);
		}
		
		// 【检验5】冻结状态下的SN不能进行料号转换
		errorList = goodsList.stream().filter(t -> Objects.equals(t.getIsHold(), IsHoldEnum.Yes.code)).collect(Collectors.toList());
		if (errorList.size() > 0) {
			List<String> errorSnList = errorList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
			String message = String.format("SN属性发生变更，SN%s被冻结不可进行料号转换！", errorSnList.toString());
			return new Result<>(false, message);
		}
		
		// 【检验6】物料品质状态必须为“合格”
		errorList = goodsList.stream().filter(t -> !Objects.equals(t.getQaStatus(), QaStatusEnum.OK.code)).collect(Collectors.toList());
		if (errorList.size() > 0) {
			List<String> errorSnList = errorList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
			List<Integer> qaStatusList = errorList.stream().map(t -> t.getQaStatus()).collect(Collectors.toList());
			List<String> qaStatusNameList = QaStatusEnum.getEnumNameByCodeList(qaStatusList);
			String message = String.format("SN属性发生变更，SN%s品质状态为%s，不能进行料号转换！", errorSnList.toString(), qaStatusNameList.toString());
			return new Result<>(false, message);
		}
		
		// 用户名、当前时间
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();
		
		// 【调拨单单头】
		TransferHeader transferHeader = new TransferHeader();
		String transferNo = basicSimpleCodeRuleApi.GenerateCode(TransferNoCodeEnum.GOODSCONVER_TRANSFER.code);
		transferHeader.setTransferNo(transferNo);
		transferHeader.setTransferType(TransferTypeEnum.T11.code);
		transferHeader.setReason("料号转换");
		transferHeader.setFmWhs(dto.getOriginalWhsId());
		transferHeader.setToWhs(dto.getOriginalWhsId());
		transferHeader.setStatus(TransferHeaderStatusEnum.FINISH.code);
		transferHeader.setCreateUser(loginName);
		transferHeader.setCreateTime(date);
		transferHeader.setModifyUser(loginName);
		transferHeader.setModifyTime(date);
		transferHeaderMapper.insert(transferHeader);
		
		int transferLineNo = 0;
		Map<String, List<GoodsVersion>> transferGoodsMap = goodsList.stream().collect(Collectors.groupingBy(t ->
			(t.getOwner() + "#" + t.getFactory() + "#" + t.getVendorId() + "#" +
		     t.getLotno() + "#" + t.getInvAttr() + "#" + t.getQaStatus() + "#"), Collectors.toList()));
		for (String transferGoodsKey : transferGoodsMap.keySet()) {
			List<GoodsVersion> transferGoodsList = transferGoodsMap.get(transferGoodsKey);
			BigDecimal qty = transferGoodsList.stream().map(t -> t.getQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
			GoodsVersion transferGoods = transferGoodsList.get(0);
			
			Lotno lotno = null;
			if(transferGoods.getLotno() != null){
				lotno = lotnoService.selectByLotno(transferGoods.getLotno());
			}
			
			// 【调拨单明细】
			TransferDtl transferDtl = new TransferDtl();
			transferDtl.setTransferNo(transferNo);
			transferDtl.setTransferHeaderId(transferHeader.getTransferHeaderId());
			transferDtl.setTransferLineNo(String.valueOf(++transferLineNo));
			transferDtl.setFmSku(transferGoods.getSkuId());
			transferDtl.setToSku(dto.getTargetSkuId());
			transferDtl.setFmOwner(transferGoods.getOwner());
			transferDtl.setToOwner(transferGoods.getOwner());
			transferDtl.setFmFactory(transferGoods.getFactory());
			transferDtl.setToFactory(transferGoods.getFactory());
			transferDtl.setFmVendor(transferGoods.getVendorId());
			transferDtl.setToVendor(transferGoods.getVendorId());
			transferDtl.setFmInvAttr(transferGoods.getInvAttr());
			transferDtl.setToInvAttr(transferGoods.getInvAttr());
			transferDtl.setFmQaStatus(transferGoods.getQaStatus());
			transferDtl.setToQaStatus(transferGoods.getQaStatus());
			transferDtl.setFmLotno(transferGoods.getLotno());
			transferDtl.setToLotno(transferGoods.getLotno());
			transferDtl.setUnit(transferGoods.getUnit());
			transferDtl.setOrderQty(qty.intValue());
			transferDtl.setCmpQty(qty.intValue());
			transferDtl.setTransitQty(0);
			transferDtl.setStatus(TransferDtlStatusEnum.FINISH.code);
			transferDtl.setCreateUser(loginName);
			transferDtl.setCreateTime(date);
			transferDtl.setModifyUser(loginName);
			transferDtl.setModifyTime(date);
			transferDtlMapper.insert(transferDtl);
			
			// 【出库凭证--单头】
			TrsnHeader fmTrsnHeader = new TrsnHeader();
			fmTrsnHeader.setNoteType(TrsnNoteTypeEnum.OUT_STORAGE.getCode());
			fmTrsnHeader.setStatus(TrsnHeaderStatusEnum.CMP.code);
			fmTrsnHeader.setNoteNo(basicSimpleCodeRuleApi.GenerateCode(TRSN_ORDER));
			fmTrsnHeader.setOwner(transferDtl.getFmOwner());
			fmTrsnHeader.setFactory(transferDtl.getFmFactory());
			fmTrsnHeader.setVendorId(transferDtl.getFmVendor());
			fmTrsnHeader.setWhsId(transferHeader.getFmWhs());
			fmTrsnHeader.setFmDoc(transferHeader.getTransferNo());
			fmTrsnHeader.setCreateUser(loginName);
			fmTrsnHeader.setCreateTime(date);
			trsnHeaderMapper.insert(fmTrsnHeader);
			
			// 【出库凭证--明细】
			TrsnDtl fmTrsnDtl = new TrsnDtl();
			fmTrsnDtl.setNoteLineNo("1");
			fmTrsnDtl.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.OUT.code);
			fmTrsnDtl.setStatus(TrsnDtlStatusEnum.CMP.code);
			fmTrsnDtl.setUnit(transferDtl.getUnit());
			fmTrsnDtl.setSkuId(transferDtl.getFmSku());
			fmTrsnDtl.setQty(qty);
			fmTrsnDtl.setFmDoc(transferDtl.getTransferNo());
			fmTrsnDtl.setQaStatus(transferDtl.getFmQaStatus());
			fmTrsnDtl.setFmDocLine(transferDtl.getTransferLineNo());
			fmTrsnDtl.setNoteNo(fmTrsnHeader.getNoteNo());
			fmTrsnDtl.setTrsnHeaderId(fmTrsnHeader.getTrsnHeaderId());
			fmTrsnDtl.setCreateUser(loginName);
			fmTrsnDtl.setCreateTime(date);
			if (lotno != null) {
				Class<?> lotnoClass = lotno.getClass();
				Class<?> trsnDtlClass = fmTrsnDtl.getClass();
				for (int i = 1; i < 13; i++) {
					Field field = lotnoClass.getDeclaredField("lotAttr" + i);
					Method method = trsnDtlClass.getMethod("setLotAttr" + i, String.class);
					field.setAccessible(true);
					method.setAccessible(true);
					method.invoke(fmTrsnDtl, field.get(lotno));
				}
			}
			trsnDtlMapper.insert(fmTrsnDtl);
			
			// 【入库凭证--单头】
			TrsnHeader toTrsnHeader = new TrsnHeader();
			toTrsnHeader.setNoteType(TrsnNoteTypeEnum.IN_STORAGE.getCode());
			toTrsnHeader.setStatus(TrsnHeaderStatusEnum.CMP.code);
			toTrsnHeader.setNoteNo(basicSimpleCodeRuleApi.GenerateCode(TRSN_ORDER));
			toTrsnHeader.setOwner(transferDtl.getToOwner());
			toTrsnHeader.setFactory(transferDtl.getToFactory());
			toTrsnHeader.setVendorId(transferDtl.getToVendor());
			toTrsnHeader.setWhsId(transferHeader.getToWhs());
			toTrsnHeader.setFmDoc(transferHeader.getTransferNo());
			toTrsnHeader.setCreateUser(loginName);
			toTrsnHeader.setCreateTime(date);
			trsnHeaderMapper.insert(toTrsnHeader);
			
			// 【入库凭证--明细】
			TrsnDtl toTrsnDtl = new TrsnDtl();
			toTrsnDtl.setNoteLineNo("1");
			toTrsnDtl.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.IN.code);
			toTrsnDtl.setStatus(TrsnDtlStatusEnum.CMP.code);
			toTrsnDtl.setUnit(transferDtl.getUnit());
			toTrsnDtl.setSkuId(transferDtl.getToSku());
			toTrsnDtl.setQty(qty);
			toTrsnDtl.setFmDoc(transferDtl.getTransferNo());
			toTrsnDtl.setQaStatus(transferDtl.getToQaStatus());
			toTrsnDtl.setFmDocLine(transferDtl.getTransferLineNo());
			toTrsnDtl.setNoteNo(toTrsnHeader.getNoteNo());
			toTrsnDtl.setTrsnHeaderId(toTrsnHeader.getTrsnHeaderId());
			toTrsnDtl.setCreateUser(loginName);
			toTrsnDtl.setCreateTime(date);
			if (lotno != null) {
				Class<?> lotnoClass = lotno.getClass();
				Class<?> trsnDtlClass = fmTrsnDtl.getClass();
				for (int i = 1; i < 13; i++) {
					Field field = lotnoClass.getDeclaredField("lotAttr" + i);
					Method method = trsnDtlClass.getMethod("setLotAttr" + i, String.class);
					field.setAccessible(true);
					method.setAccessible(true);
					method.invoke(toTrsnDtl, field.get(lotno));
				}
			}
			trsnDtlMapper.insert(toTrsnDtl);
			
			for (GoodsVersion goods : transferGoodsList) {
				// 【调拨单明细货品清单】
				TransferDtlGoods transferDtlGoods = new TransferDtlGoods();
				transferDtlGoods.setTransferDtlId(transferDtl.getTransferDtlId());
				transferDtlGoods.setGoodsSn(goods.getGoodsSn());
				transferDtlGoods.setGoodsId(goods.getGoodsId());
				transferDtlGoods.setQaStatus(goods.getQaStatus());
				transferDtlGoods.setQty(goods.getQty());
				transferDtlGoods.setStatus(TransferDtlGoodStatusEnum.HAS_RECEIVE.code);
				transferDtlGoods.setCreateUser(loginName);
				transferDtlGoods.setCreateTime(date);
				transferDtlGoodsMapper.insert(transferDtlGoods);
				
				// 【出库凭证--明细goods】
				TrsnDtlGoods fmTrsnDtlGoods = new TrsnDtlGoods();
				fmTrsnDtlGoods.setTrsnDtlId(fmTrsnDtl.getTrsnDtlId());
				fmTrsnDtlGoods.setGoodsSn(goods.getGoodsSn());
				fmTrsnDtlGoods.setGoodsId(goods.getGoodsId());
				fmTrsnDtlGoods.setQty(goods.getQty());
				fmTrsnDtlGoods.setQaStatus(goods.getQaStatus());
				fmTrsnDtlGoods.setStatus(TransferDtlGoodStatusEnum.HAS_RECEIVE.code);
				fmTrsnDtlGoods.setCreateTime(date);
				fmTrsnDtlGoods.setCreateUser(loginName);
				trsnDtlGoodsMapper.insert(fmTrsnDtlGoods);
				
				// 【入库凭证--明细goods】
				TrsnDtlGoods toTrsnDtlGoods = new TrsnDtlGoods();
				toTrsnDtlGoods.setTrsnDtlId(toTrsnDtl.getTrsnDtlId());
				toTrsnDtlGoods.setGoodsSn(goods.getGoodsSn());
				toTrsnDtlGoods.setGoodsId(goods.getGoodsId());
				toTrsnDtlGoods.setQty(goods.getQty());
				toTrsnDtlGoods.setQaStatus(goods.getQaStatus());
				toTrsnDtlGoods.setStatus(TransferDtlGoodStatusEnum.HAS_RECEIVE.code);
				toTrsnDtlGoods.setCreateTime(date);
				toTrsnDtlGoods.setCreateUser(loginName);
				trsnDtlGoodsMapper.insert(toTrsnDtlGoods);
				
				// 【更新goods】
				GoodsVersion updateGoods = new GoodsVersion();
				updateGoods.setGoodsId(goods.getGoodsId());				// 条码ID
				updateGoods.setVersion(goods.getVersion());				// 数据版本
				updateGoods.setSkuId(dto.getTargetSkuId());				// 目标物料
				updateGoods.setModifyUser(loginName);
				updateGoods.setModifyTime(date);
				goodsVersionService.updateById(updateGoods);
				
				String oldGoodsJson = JSON.toJSONString(goods); 		// 原先的json
				String newGoodsJson = JSON.toJSONString(updateGoods); 	// 更新后的json
				
				// 【新增goods日志】
				GoodsLog goodsLog = new GoodsLog();
				goodsLog.setGoodsSn(goods.getGoodsSn());
				goodsLog.setOpCode(OpCodeEnum.TRANSFER.getCode());
				goodsLog.setReason(String.format("料号转换，调拨单[%s/%s]", transferDtl.getTransferNo(), transferDtl.getTransferLineNo()));
				goodsLog.setUpdateContent("未更新的:" + oldGoodsJson + ",更新的:" + newGoodsJson);
				goodsLog.setOperator(loginName);
				goodsLog.setCreateUser(loginName);
				goodsLog.setCreateTime(date);
				goodsService.insertGoodsLog(goodsLog);
			}
		}
		
		// 【表更库存】
		// 根据【仓库、库位、货主、物料、组织、供应商、批次号、库存性质、品质状态】分组统计
		Map<String, List<GoodsVersion>> goodsMap = goodsList.stream().collect(Collectors.groupingBy(t ->
			(t.getWhsId() + "#" + t.getLocId() + "#" + t.getOwner() + "#" +
			t.getSkuId() + "#" + t.getFactory() + "#" + t.getVendorId() + "#" +
			t.getLotno() + "#" + t.getInvAttr() + "#" + t.getQaStatus() + "#"), Collectors.toList()));
		for (String goodsKey : goodsMap.keySet()) {
			goodsList = goodsMap.get(goodsKey);
			BigDecimal qty = goodsList.stream().map(t -> t.getQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
			GoodsVersion goods = goodsList.get(0);

			// 【更新库存】
			// 扣减原物料编码库位库存
			UpdateInventoryInputDto input = new UpdateInventoryInputDto();
			input.setWhsId(goods.getWhsId()); 		// 仓库
			input.setOwner(goods.getOwner()); 		// 货主
			input.setSkuId(goods.getSkuId()); 		// 【原物料】
			input.setFactory(goods.getFactory()); 	// 组织
			input.setVendorId(goods.getVendorId()); // 供应商
			input.setInvAttr(goods.getInvAttr()); 	// 库存性质
			input.setQaStatus(goods.getQaStatus()); // QA状态
			input.setLocId(goods.getLocId()); 		// 库位ID
			input.setUnit(goods.getUnit()); 		// 单位
			input.setQty(qty.negate()); 			// 【数量-】
			input.setOperator(loginName);
			inventoryService.updateLocInventroy(input);
			inventoryService.updateZoneInventory(input);
			
			// 增加目标物料编码库位库存
			input.setSkuId(dto.getTargetSkuId());	// 【目标物料】
			input.setQty(qty);						// 【数量+】
			inventoryService.updateLocInventroy(input);
			inventoryService.updateZoneInventory(input);
		}

		// 调用SAP接口
        try {
        	Sku sourceSku = skuMapper.selectById(dto.getOriginalSkuId());	// 源物料
    		Sku targetSku = skuMapper.selectById(dto.getTargetSkuId()); 	// 目标物料
    		
			BigDecimal menge = goodsList.stream().map(t -> t.getQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
			
			String mappingHouse = mappingHouseService.getSapHouseByWhsId(dto.getOriginalWhsId(), dto.getOriginalFactory());

			ZDT_085_ReqRECORDHEAD record= new ZDT_085_ReqRECORDHEAD();
			record.setWERKS(dto.getOriginalFactory());  //调出工厂
			record.setLGORT(mappingHouse);  			//调出仓库
			record.setMATNR(sourceSku.getSkuCode());  	//调出物料
			record.setMENGE(menge.toString());  		//调出数量
			record.setUMMAT(targetSku.getSkuCode());  	//调入物料
			record.setUMLGO(mappingHouse); 				//调入仓库
			materialReplaceWriteOffService.backToSap(record);
		} catch (SystemException e) {
			Shift.fatal(e.getMessage());
		} catch (Exception e) {
			e.printStackTrace();
			Shift.fatal("调用SAP接口失败");
		}
		return new Result<>();
	}
}
